Proper connect_port
[juce-lv2.git] / juce / source / extras / the jucer / src / model / paintelements / jucer_PaintElement.cpp
blob54d41e25a662504ae2deffb2e16f528a9be7771b
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../jucer_Headers.h"
27 #include "../jucer_PaintRoutine.h"
28 #include "../../ui/jucer_PaintRoutineEditor.h"
29 #include "../../properties/jucer_PositionPropertyBase.h"
30 #include "jucer_ElementSiblingComponent.h"
31 #include "jucer_PaintElementUndoableAction.h"
34 //==============================================================================
35 PaintElement::PaintElement (PaintRoutine* owner_,
36 const String& typeName_)
37 : owner (owner_),
38 typeName (typeName_),
39 selected (false),
40 dragging (false),
41 borderThickness (4),
42 originalAspectRatio (1.0)
44 setRepaintsOnMouseActivity (true);
46 position.rect.setWidth (100);
47 position.rect.setHeight (100);
49 setMinimumOnscreenAmounts (0, 0, 0, 0);
50 setSizeLimits (borderThickness * 2 + 1, borderThickness * 2 + 1, 8192, 8192);
52 addChildComponent (border = new ResizableBorderComponent (this, this));
54 border->setBorderThickness (BorderSize<int> (borderThickness));
56 if (owner != 0)
57 owner->getSelectedElements().addChangeListener (this);
59 selfChangeListenerList.addChangeListener (this);
60 siblingComponentsChanged();
63 PaintElement::~PaintElement()
65 siblingComponents.clear();
67 if (owner != 0)
68 owner->getSelectedElements().removeChangeListener (this);
70 delete border;
74 //==============================================================================
75 void PaintElement::setInitialBounds (int parentWidth, int parentHeight)
77 RelativePositionedRectangle pr (getPosition());
78 pr.rect.setX (parentWidth / 4 + Random::getSystemRandom().nextInt (parentWidth / 4) - parentWidth / 8);
79 pr.rect.setY (parentHeight / 3 + Random::getSystemRandom().nextInt (parentHeight / 4) - parentHeight / 8);
80 setPosition (pr, false);
83 //==============================================================================
84 const RelativePositionedRectangle& PaintElement::getPosition() const
86 return position;
89 class PaintElementMoveAction : public PaintElementUndoableAction <PaintElement>
91 public:
92 PaintElementMoveAction (PaintElement* const element, const RelativePositionedRectangle& newState_)
93 : PaintElementUndoableAction <PaintElement> (element),
94 newState (newState_),
95 oldState (element->getPosition())
99 bool perform()
101 showCorrectTab();
102 getElement()->setPosition (newState, false);
103 return true;
106 bool undo()
108 showCorrectTab();
109 getElement()->setPosition (oldState, false);
110 return true;
113 private:
114 RelativePositionedRectangle newState, oldState;
117 void PaintElement::setPosition (const RelativePositionedRectangle& newPosition, const bool undoable)
119 if (position != newPosition)
121 if (undoable)
123 perform (new PaintElementMoveAction (this, newPosition),
124 "Move " + getTypeName());
126 else
128 position = newPosition;
130 if (owner != 0)
131 owner->changed();
136 //==============================================================================
137 const Rectangle<int> PaintElement::getCurrentBounds (const Rectangle<int>& parentArea) const
139 return position.getRectangle (parentArea, getDocument()->getComponentLayout());
142 void PaintElement::setCurrentBounds (const Rectangle<int>& newBounds,
143 const Rectangle<int>& parentArea,
144 const bool undoable)
146 RelativePositionedRectangle pr (position);
147 pr.updateFrom (newBounds.getX() - parentArea.getX(),
148 newBounds.getY() - parentArea.getY(),
149 jmax (1, newBounds.getWidth()),
150 jmax (1, newBounds.getHeight()),
151 Rectangle<int> (0, 0, parentArea.getWidth(), parentArea.getHeight()),
152 getDocument()->getComponentLayout());
154 setPosition (pr, undoable);
156 updateBounds (parentArea);
159 void PaintElement::updateBounds (const Rectangle<int>& parentArea)
161 if (! parentArea.isEmpty())
163 setBounds (getCurrentBounds (parentArea)
164 .expanded (borderThickness,
165 borderThickness));
167 for (int i = siblingComponents.size(); --i >= 0;)
168 siblingComponents.getUnchecked(i)->updatePosition();
172 //==============================================================================
173 class ElementPositionProperty : public PositionPropertyBase
175 public:
176 //==============================================================================
177 ElementPositionProperty (PaintElement* element_,
178 const String& name,
179 ComponentPositionDimension dimension_)
180 : PositionPropertyBase (element_, name, dimension_, true, false,
181 element_->getDocument()->getComponentLayout()),
182 element (element_)
184 element_->getDocument()->addChangeListener (this);
187 ~ElementPositionProperty()
189 element->getDocument()->removeChangeListener (this);
192 //==============================================================================
193 void setPosition (const RelativePositionedRectangle& newPos)
195 element->setPosition (newPos, true);
198 const RelativePositionedRectangle getPosition() const
200 return element->getPosition();
203 private:
204 PaintElement* const element;
207 //==============================================================================
208 void PaintElement::getEditableProperties (Array <PropertyComponent*>& properties)
210 properties.add (new ElementPositionProperty (this, "x", PositionPropertyBase::componentX));
211 properties.add (new ElementPositionProperty (this, "y", PositionPropertyBase::componentY));
212 properties.add (new ElementPositionProperty (this, "width", PositionPropertyBase::componentWidth));
213 properties.add (new ElementPositionProperty (this, "height", PositionPropertyBase::componentHeight));
216 //==============================================================================
217 JucerDocument* PaintElement::getDocument() const
219 return owner->getDocument();
222 void PaintElement::changed()
224 repaint();
225 owner->changed();
228 bool PaintElement::perform (UndoableAction* action, const String& actionName)
230 return owner->perform (action, actionName);
233 void PaintElement::parentHierarchyChanged()
235 updateSiblingComps();
238 //==============================================================================
239 void PaintElement::drawExtraEditorGraphics (Graphics& g, const Rectangle<int>& relativeTo)
243 void PaintElement::paint (Graphics& g)
245 Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
247 g.saveState();
248 g.setOrigin (area.getX() - getX(), area.getY() - getY());
249 area.setPosition (0, 0);
251 g.saveState();
252 g.reduceClipRegion (0, 0, area.getWidth(), area.getHeight());
254 draw (g, getDocument()->getComponentLayout(), area);
256 g.restoreState();
258 drawExtraEditorGraphics (g, area);
259 g.restoreState();
261 if (selected)
263 const BorderSize<int> borderSize (border->getBorderThickness());
265 drawResizableBorder (g, getWidth(), getHeight(), borderSize,
266 (isMouseOverOrDragging() || border->isMouseOverOrDragging()));
268 else if (isMouseOverOrDragging())
270 drawMouseOverCorners (g, getWidth(), getHeight());
274 void PaintElement::resized()
276 border->setBounds (0, 0, getWidth(), getHeight());
279 void PaintElement::mouseDown (const MouseEvent& e)
281 dragging = false;
283 if (owner != 0)
285 owner->getSelectedPoints().deselectAll();
286 mouseDownSelectStatus = owner->getSelectedElements().addToSelectionOnMouseDown (this, e.mods);
289 if (e.mods.isPopupMenu())
291 showPopupMenu();
292 return; // this may be deleted now..
296 void PaintElement::mouseDrag (const MouseEvent& e)
298 if (! e.mods.isPopupMenu())
300 jassert (dynamic_cast <PaintRoutineEditor*> (getParentComponent()) != 0);
301 const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
303 if (selected && ! dragging)
305 dragging = ! e.mouseWasClicked();
307 if (dragging)
308 owner->startDragging (area);
311 if (dragging)
312 owner->dragSelectedComps (e.getDistanceFromDragStartX(),
313 e.getDistanceFromDragStartY(),
314 area);
318 void PaintElement::mouseUp (const MouseEvent& e)
320 if (dragging)
321 owner->endDragging();
323 if (owner != 0)
324 owner->getSelectedElements().addToSelectionOnMouseUp (this, e.mods, dragging, mouseDownSelectStatus);
327 void PaintElement::resizeStart()
329 if (getHeight() > 0)
330 originalAspectRatio = getWidth() / (double) getHeight();
331 else
332 originalAspectRatio = 1.0;
335 void PaintElement::resizeEnd()
339 void PaintElement::checkBounds (Rectangle<int>& bounds,
340 const Rectangle<int>& previousBounds,
341 const Rectangle<int>& limits,
342 const bool isStretchingTop,
343 const bool isStretchingLeft,
344 const bool isStretchingBottom,
345 const bool isStretchingRight)
347 if (ModifierKeys::getCurrentModifiers().isShiftDown())
348 setFixedAspectRatio (originalAspectRatio);
349 else
350 setFixedAspectRatio (0.0);
352 ComponentBoundsConstrainer::checkBounds (bounds, previousBounds, limits, isStretchingTop, isStretchingLeft, isStretchingBottom, isStretchingRight);
354 JucerDocument* document = getDocument();
356 if (document != 0 && document->isSnapActive (true))
358 jassert (getParentComponent() != 0);
359 const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
361 int x = bounds.getX();
362 int y = bounds.getY();
363 int w = bounds.getWidth();
364 int h = bounds.getHeight();
366 x += borderThickness - area.getX();
367 y += borderThickness - area.getY();
368 w -= borderThickness * 2;
369 h -= borderThickness * 2;
371 int right = x + w;
372 int bottom = y + h;
374 if (isStretchingRight)
375 right = document->snapPosition (right);
377 if (isStretchingBottom)
378 bottom = document->snapPosition (bottom);
380 if (isStretchingLeft)
381 x = document->snapPosition (x);
383 if (isStretchingTop)
384 y = document->snapPosition (y);
386 w = (right - x) + borderThickness * 2;
387 h = (bottom - y) + borderThickness * 2;
388 x -= borderThickness - area.getX();
389 y -= borderThickness - area.getY();
391 bounds = Rectangle<int> (x, y, w, h);
395 void PaintElement::applyBoundsToComponent (Component* component, const Rectangle<int>& bounds)
397 if (getBounds() != bounds)
399 getDocument()->getUndoManager().undoCurrentTransactionOnly();
401 jassert (dynamic_cast <PaintRoutineEditor*> (getParentComponent()) != 0);
403 setCurrentBounds (bounds.expanded (-borderThickness, -borderThickness),
404 ((PaintRoutineEditor*) getParentComponent())->getComponentArea(),
405 true);
409 const Rectangle<int> PaintElement::getCurrentAbsoluteBounds() const
411 jassert (dynamic_cast <PaintRoutineEditor*> (getParentComponent()) != 0);
412 const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
414 return position.getRectangle (area, getDocument()->getComponentLayout());
417 void PaintElement::getCurrentAbsoluteBoundsDouble (double& x, double& y, double& w, double& h) const
419 jassert (dynamic_cast <PaintRoutineEditor*> (getParentComponent()) != 0);
420 const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
422 position.getRectangleDouble (x, y, w, h, area, getDocument()->getComponentLayout());
425 void PaintElement::changeListenerCallback (ChangeBroadcaster*)
427 const bool nowSelected = owner != 0 && owner->getSelectedElements().isSelected (this);
429 if (selected != nowSelected)
431 selected = nowSelected;
432 border->setVisible (nowSelected);
433 repaint();
435 selectionChanged (nowSelected);
438 updateSiblingComps();
441 void PaintElement::selectionChanged (const bool isSelected)
445 void PaintElement::createSiblingComponents()
449 void PaintElement::siblingComponentsChanged()
451 siblingComponents.clear();
452 selfChangeListenerList.sendChangeMessage();
455 void PaintElement::updateSiblingComps()
457 if (selected && getParentComponent() != 0 && owner->getSelectedElements().getNumSelected() == 1)
459 if (siblingComponents.size() == 0)
460 createSiblingComponents();
462 for (int i = siblingComponents.size(); --i >= 0;)
463 siblingComponents.getUnchecked(i)->updatePosition();
465 else
467 siblingComponents.clear();
472 void PaintElement::showPopupMenu()
474 PopupMenu m;
476 m.addCommandItem (commandManager, CommandIDs::toFront);
477 m.addCommandItem (commandManager, CommandIDs::toBack);
478 m.addSeparator();
479 m.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
480 m.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
481 m.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
482 m.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
484 m.show();